<template>
    <div class="box-border size-full relative" :class="wrapperClass" :style="wrapperStyle">
        <a-input v-bind="$attrs" v-model:value="state.value" @change="updateValue" @blur="handleBlur" @focus="handleFocus"/>
        <a-select
            style="width: 100%; height: 0; overflow: hidden; position: absolute; top: 0; left: 0;"
            :open="open"
            show-search
            :show-arrow="false"
            :filter-option="false" 
            :not-found-content="state.fetching ? undefined : null"
            :options="state.data"
            :size="$attrs.size"
            @change="handleSelectChange"
        >
            <template v-if="state.fetching" #notFoundContent>
                <a-spin size="small" />
            </template>
        </a-select>
    </div>
</template>
<script lang="ts" setup>
import type { ChangeEventHandler } from 'ant-design-vue/es/_util/EventInterface';
import type { DefaultOptionType, SelectProps, SelectValue } from 'ant-design-vue/es/select';
import type { StyleValue } from 'vue';

type State = {
    data: DefaultOptionType[]
    value?: string
    fetching: boolean
};
defineOptions({
    name: 'GpEditableSearchSelect',
    inheritAttrs: false
});
const emit = defineEmits<{
    change: [value: string]
    select: [value: SelectValue, option: DefaultOptionType]
}>()
const { getOptions } = defineProps<{
    wrapperStyle?: StyleValue
    wrapperClass?: any
    getOptions(text: string): Promise<DefaultOptionType[]>
}>()
const selectValue = defineModel<string>("value")
let lastFetchId = 0;
const state = reactive<State>({
    data: [],
    value: selectValue.value!,
    fetching: false,
});
const open = ref(false)
const fetchOptions = debounce(300, fetcher);
async function fetcher(value: string) {
    lastFetchId += 1;
    const fetchId = lastFetchId;
    state.data = [];
    state.fetching = true;
    open.value = true;
    const data = await getOptions(value)
    if (fetchId !== lastFetchId) {
        return;
    }
    state.data = data;
    state.fetching = false;

}
const syncValue = (value: string) => {
    state.value = value
    selectValue.value = value
    emit('change', value)
}
const updateValue: ChangeEventHandler = (e) => {
    const value = e.target.value!
    syncValue(value)
    fetchOptions(value)
}
const handleSelectChange:SelectProps['onChange'] = (value, option) => {
    emit('select', value, option)
    open.value = false
}
function handleBlur() {
    open.value = false
}
function handleFocus() {
    if (
        open.value === false
        && state.data.length > 0
    ) open.value = true
}
useEffectScope(() => {
    watch(selectValue, () => {
        state.value = selectValue.value
    })
})
</script>